"""
文件上传相关业务逻辑服务 (services/upload_service.py)

处理文件上传、保存、记录管理和查询。
"""
from models.upload import (
    load_uploads, get_date_folder_path, 
    get_upload_by_id, get_upload_dates, create_upload_record,
    update_upload_tags as update_upload_tags_model
)
from utils.file_utils import allowed_file, ensure_directory_exists
from config.config import APP_CONFIG
from services.openai_service import get_image_tags
from models.db_models import Upload as UploadDB
from models import db_session
import os
import uuid
import shutil
from werkzeug.utils import secure_filename
import logging
from datetime import datetime

logger = logging.getLogger(__name__)

def handle_file_upload(files, tags=None):
    """
    处理文件上传。
    保存文件到按日期分类的目录，并记录元数据。

    Args:
        files: 文件列表 (来自 request.files.getlist)。
        tags: 标签 (字符串或列表, 可选)。

    Returns:
        tuple: (上传成功的文件信息列表, None) 或 (None, 错误信息)
    """
    if not files or (len(files) == 1 and files[0].filename == ''):
        logger.warning("上传请求中未选择文件")
        return None, "未选择任何文件"
    
    tag_list = []
    if tags:
        if isinstance(tags, str):
            tag_list = [tag.strip() for tag in tags.split(',') if tag.strip()]
        elif isinstance(tags, list):
            tag_list = [str(tag).strip() for tag in tags if str(tag).strip()]
    
    date_folder_path, date_str = get_date_folder_path()
    ensure_directory_exists(date_folder_path)
    
    uploaded_files_info = []
    
    for file in files:
        if file and allowed_file(file.filename, APP_CONFIG['ALLOWED_EXTENSIONS']):
            original_filename = secure_filename(file.filename)
            
            file_id = str(uuid.uuid4())
            unique_filename = f"{file_id}_{original_filename}"
            
            file_path = os.path.join(date_folder_path, unique_filename)
            
            try:
                # 保存文件到文件系统
                file.save(file_path)
                logger.info(f"文件已保存: {file_path}")
                
                # 构建URL和文件信息
                file_url = f"/api/uploads/{date_str}/{unique_filename}"
                
                # 获取文件大小
                file_size = os.path.getsize(file_path) if os.path.exists(file_path) else None
                # 获取文件类型
                file_type = file.content_type if hasattr(file, 'content_type') else None
                
                # 创建上传记录 - 使用create_upload_record保存到MySQL
                upload_record = create_upload_record(
                    file_id=file_id,
                    original_name=original_filename,
                    saved_name=unique_filename,
                    url=file_url,
                    file_path=file_path,
                    file_size=file_size,
                    file_type=file_type,
                    date_folder=date_folder_path
                )
                
                # 添加标签
                if tag_list:
                    # 调用update_upload_tags以确保标签计数被更新
                    update_upload_tags_model(file_id, tag_list)
                
                # 添加兼容性字段
                upload_record['filename'] = unique_filename
                upload_record['path'] = f"{date_str}/{unique_filename}"
                upload_record['uploadedAt'] = upload_record.get('createdAt') or get_timestamp()
                
                uploaded_files_info.append(upload_record)
                
            except Exception as e:
                logger.error(f"保存文件 {original_filename} 时出错: {e}")
                continue
        else:
            if file:
                logger.warning(f"跳过不允许的文件类型: {file.filename}")
            continue
    
    if uploaded_files_info:
        logger.info(f"成功上传 {len(uploaded_files_info)} 个文件到日期 {date_str}")
        return uploaded_files_info, None
    else:
        logger.warning("没有有效文件被上传")
        return None, "没有有效文件被上传或保存失败"

def get_all_uploads():
    """
    获取所有上传记录（包括所有日期和旧记录）。
    
    Returns:
        list: 所有上传记录，按时间降序。
    """
    all_uploads = []
    
    upload_dates = get_upload_dates()
    for date_info in upload_dates:
        date_folder = os.path.join(APP_CONFIG['UPLOAD_FOLDER'], date_info['date'])
        uploads = load_uploads(date_folder)
        all_uploads.extend(uploads)
    
    legacy_uploads = load_uploads()
    all_uploads.extend(legacy_uploads)
    
    all_uploads.sort(key=lambda x: x.get('uploadedAt', '1970-01-01T00:00:00Z'), reverse=True)
    
    return all_uploads

def get_upload(file_id):
    """
    根据文件 ID 获取单个上传记录。
    优先搜索日期文件夹，然后搜索根目录。

    Args:
        file_id: 文件 ID。

    Returns:
        tuple: (上传记录字典, None) 或 (None, 错误信息)
    """
    upload_dates = get_upload_dates()
    for date_info in upload_dates:
        date_folder = os.path.join(APP_CONFIG['UPLOAD_FOLDER'], date_info['date'])
        upload = get_upload_by_id(file_id, date_folder)
        if upload:
            return upload, None
    
    upload = get_upload_by_id(file_id)
    if upload:
        return upload, None
        
    logger.warning(f"未找到上传记录 ID: {file_id}")
    return None, "上传记录未找到"

def update_upload_tags(file_id, tags):
    """
    更新指定上传记录的标签。

    Args:
        file_id: 文件 ID。
        tags (list): 新的标签列表。

    Returns:
        tuple: (更新后的记录字典, None) 或 (None, 错误信息)
    """
    if not isinstance(tags, list):
        logger.warning(f"更新标签失败：提供的标签不是列表格式 (ID: {file_id})")
        return None, "标签必须是列表格式"
        
    cleaned_tags = [str(tag).strip() for tag in tags if str(tag).strip()]

    updated_upload = update_upload_tags_model(file_id, cleaned_tags)
    if updated_upload:
        logger.info(f"已更新数据库中文件 {file_id} 的标签")
        return updated_upload, None
    else:
        logger.warning(f"更新标签失败：未找到文件 ID {file_id}")
        return None, "未找到文件记录或更新失败"

def get_uploads_by_date(date):
    """
    获取指定日期的上传记录。

    Args:
        date: 日期字符串 (YYYYMMDD格式)。

    Returns:
        tuple: (上传记录列表, None) 或 (None, 错误信息)
    """
    if not date:
        logger.warning("未提供日期")
        return None, "请提供有效的日期 (YYYYMMDD格式)"
    
    date_folder = os.path.join(APP_CONFIG['UPLOAD_FOLDER'], date)
    
    if not os.path.exists(date_folder):
        logger.warning(f"日期文件夹不存在: {date}")
        return None, f"找不到日期 {date} 的上传记录"
    
    uploads = load_uploads(date_folder)
    return uploads, None

def get_timestamp():
    """获取当前UTC时间戳字符串。"""
    return datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")

def import_files_from_directory(target_date=None, analyze_images=False):
    """
    从导入目录（uploads/import/）导入图片文件。
    如果提供了target_date，则将文件导入到该日期的目录下。
    如果analyze_images为True，则使用AI分析图片生成标签。

    Args:
        target_date: 目标日期 (YYYYMMDD格式，可选)。
        analyze_images: 是否使用AI分析图片 (默认: False)。

    Returns:
        tuple: (导入结果字典, None) 或 (None, 错误信息)
    """
    print(APP_CONFIG['UPLOAD_FOLDER'])
    import_source_dir = os.path.join(APP_CONFIG['UPLOAD_FOLDER'], 'import')
    
    # 确保导入目录存在
    if not os.path.exists(import_source_dir):
        os.makedirs(import_source_dir)
        return None, "导入目录不存在，已创建 uploads/import 目录，请先放入图片后再导入"
    
    # 获取所有图片文件
    import_files = []
    invalid_files = []
    unsupported_files = []
    
    for filename in os.listdir(import_source_dir):
        file_path = os.path.join(import_source_dir, filename)
        # 检查是否是文件
        if not os.path.isfile(file_path):
            continue
        # 检查是否是支持的文件格式
        if not allowed_file(filename, APP_CONFIG['ALLOWED_EXTENSIONS']):
            extension = os.path.splitext(filename)[1].lower()[1:] if '.' in filename else '无扩展名'
            unsupported_files.append((filename, extension))
            continue
        # 检查文件是否完整/可读
        try:
            # 尝试读取文件以验证其完整性
            with open(file_path, 'rb') as f:
                if f.read(1):  # 尝试读取至少1个字节
                    import_files.append((filename, file_path))
                else:
                    invalid_files.append((filename, "文件为空"))
        except Exception as e:
            invalid_files.append((filename, f"文件读取错误: {str(e)}"))
    
    # 错误处理：没有找到有效文件
    if not import_files:
        error_message = "导入目录中没有找到有效的图片文件"
        if not os.listdir(import_source_dir):
            error_message = "导入目录为空，请先在 uploads/import 目录中放入图片文件"
        elif unsupported_files:
            supported_formats = ", ".join(APP_CONFIG['ALLOWED_EXTENSIONS'])
            error_message = f"导入目录中没有支持的图片格式，仅支持: {supported_formats}"
            if len(unsupported_files) <= 5:
                file_list = ", ".join([f"{name}({ext})" for name, ext in unsupported_files])
                error_message += f"。找到的不支持文件: {file_list}"
            else:
                error_message += f"。找到{len(unsupported_files)}个不支持的文件"
        elif invalid_files:
            error_message = "导入目录中的文件都无法读取或损坏"
        
        return None, error_message
    
    # 确定目标日期目录
    if target_date:
        # 验证日期格式
        if not (isinstance(target_date, str) and len(target_date) == 8 and target_date.isdigit()):
            return None, "无效的日期格式，请使用 YYYYMMDD 格式，例如 20240415"
        
        # 进一步验证日期的有效性
        try:
            year = int(target_date[:4])
            month = int(target_date[4:6])
            day = int(target_date[6:8])
            
            if not (1900 <= year <= 2100 and 1 <= month <= 12 and 1 <= day <= 31):
                return None, f"无效的日期值: {year}年{month}月{day}日，请检查日期范围"
        except ValueError:
            return None, "日期解析错误，请使用 YYYYMMDD 格式，例如 20240415"
            
        # 使用指定的目标日期
        target_date_folder = os.path.join(APP_CONFIG['UPLOAD_FOLDER'], target_date)
    else:
        # 使用当前日期
        target_date_folder, target_date = get_date_folder_path()
    
    # 确保目标目录存在
    try:
        ensure_directory_exists(target_date_folder)
    except Exception as e:
        return None, f"创建目标日期目录时出错: {str(e)}"
    
    # 准备导入结果
    import_results = {
        "importedFiles": [],
        "failedFiles": [],
        "totalCount": len(import_files),
        "importedCount": 0,
        "skippedCount": 0,
        "date": target_date,
        "unsupportedFiles": len(unsupported_files)
    }
    
    for original_filename, file_path in import_files:
        try:
            # 安全化文件名并生成UUID
            file_id = str(uuid.uuid4())
            secure_name = secure_filename(original_filename)
            unique_filename = f"{file_id}_{secure_name}"
            
            # 目标文件路径
            target_file_path = os.path.join(target_date_folder, unique_filename)
            
            # 复制文件
            shutil.copy2(file_path, target_file_path)
            logger.info(f"已复制文件: {original_filename} -> {target_file_path}")
            
            # 获取文件大小
            file_size = os.path.getsize(target_file_path)
            
            # 构建URL
            file_url = f"/api/uploads/{target_date}/{unique_filename}"
            
            # 初始标签列表
            tags = []
            ai_analysis_result = None
            
            # 如果启用AI分析，获取图片标签
            if analyze_images:
                try:
                    ai_tags = get_image_tags(target_file_path)
                    if ai_tags and 'cn_tags' in ai_tags:
                        logger.info(f"AI分析生成标签: {ai_tags}")
                        tags = ai_tags.get('cn_tags', [])
                        ai_analysis_result = ai_tags
                except Exception as e:
                    logger.error(f"AI分析图片时出错: {e}")
            
            # 创建上传记录
            upload_record = create_upload_record(
                file_id=file_id,
                original_name=original_filename,
                saved_name=unique_filename,
                url=file_url,
                file_path=target_file_path,
                file_size=file_size,
                file_type=None,  # 不确定MIME类型
                date_folder=target_date_folder,
                analyzed=analyze_images,
                ai_analysis=ai_analysis_result
            )
            
            # 如果有标签，更新记录
            if tags:
                update_upload_tags_model(file_id, tags)
                upload_record['tags'] = tags
            
            import_results["importedFiles"].append({
                "id": file_id,
                "originalName": original_filename,
                "savedName": unique_filename,
                "url": file_url,
                "tags": tags,
                "size": file_size
            })
            
            import_results["importedCount"] += 1
            
            # 导入成功后删除原文件
            try:
                os.remove(file_path)
                logger.info(f"已删除原文件: {file_path}")
            except Exception as e:
                logger.warning(f"删除原文件时出错: {e}")
            
        except Exception as e:
            logger.error(f"导入文件 {original_filename} 时出错: {e}")
            import_results["failedFiles"].append({
                "filename": original_filename,
                "error": str(e)
            })
            import_results["skippedCount"] += 1
    
    if import_results["importedCount"] > 0:
        return import_results, None
    else:
        if len(import_results["failedFiles"]) > 0:
            # 分析失败原因，提供更详细的错误信息
            errors = [item["error"] for item in import_results["failedFiles"]]
            if all("权限被拒绝" in e for e in errors):
                return None, "所有文件导入失败：文件权限不足，请检查文件夹权限设置"
            elif all("磁盘空间不足" in e for e in errors):
                return None, "所有文件导入失败：目标磁盘空间不足"
            else:
                # 取前三个错误作为示例
                example_errors = errors[:3]
                return None, f"所有文件导入失败，常见错误: {', '.join(example_errors)}"
        else:
            return None, "所有文件导入失败，请检查日志获取详细信息"

def get_recent_imports(limit=20):
    """
    获取最近导入的图片文件列表。
    
    Args:
        limit: 返回结果数量限制 (默认20)。
    
    Returns:
        list: 最近导入的图片记录列表。
    """
    try:
        session = db_session()
        
        # 查询最近的上传记录，按创建时间降序排序
        recent_imports = session.query(UploadDB).order_by(UploadDB.created_at.desc()).limit(limit).all()
        
        # 转换为字典列表
        results = []
        for upload in recent_imports:
            results.append({
                "id": upload.id,
                "name": upload.name,
                "url": upload.url,
                "originalName": upload.original_name,
                "savedName": upload.saved_name,
                "createdAt": upload.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if upload.created_at else None,
                "fileSize": upload.file_size,
                "fileType": upload.file_type,
                "dateFolder": upload.date_folder,
                "analyzed": upload.analyzed,
                "tags": upload.tags if upload.tags else []
            })
        
        session.close()
        return results
    except Exception as e:
        logger.error(f"获取最近导入列表时出错: {e}")
        return []

def sync_tags_from_uploads():
    """
    同步所有上传文件的标签到标签表。
    重新计算每个标签的使用次数，并更新数据库。
    
    Returns:
        tuple: (同步结果字典, None) 或 (None, 错误信息)
    """
    try:
        session = db_session()
        
        # 查询所有上传记录的标签
        uploads = session.query(UploadDB).all()
        
        # 生成标签统计信息
        tag_statistics = {}
        for upload in uploads:
            if not upload.tags:
                continue
            
            for tag in upload.tags:
                if tag in tag_statistics:
                    tag_statistics[tag] += 1
                else:
                    tag_statistics[tag] = 1
        
        # 获取现有标签
        from models.db_models import Tag
        existing_tags = session.query(Tag).all()
        existing_tag_names = {tag.name: tag for tag in existing_tags}
        
        # 更新现有标签和添加新标签
        current_time = datetime.utcnow()
        created_count = 0
        updated_count = 0
        
        for tag_name, count in tag_statistics.items():
            if tag_name in existing_tag_names:
                # 更新现有标签
                tag = existing_tag_names[tag_name]
                tag.count = count
                tag.last_used = current_time
                updated_count += 1
            else:
                # 创建新标签
                new_tag = Tag(
                    name=tag_name,
                    count=count,
                    created_at=current_time,
                    last_used=current_time
                )
                session.add(new_tag)
                created_count += 1
        
        # 保存更改
        session.commit()
        session.close()
        
        # 返回同步结果
        return {
            "total_uploads": len(uploads),
            "total_tags": len(tag_statistics),
            "updated_tags": updated_count,
            "created_tags": created_count,
            "tag_counts": tag_statistics
        }, None
    except Exception as e:
        logger.error(f"同步标签数据时出错: {e}")
        if session:
            session.rollback()
            session.close()
        return None, f"同步标签数据时出错: {str(e)}"    